/* 
 * File:   LinuxFileInfo.h
 * Author: ariel
 *
 * Created on 11 de septiembre de 2009, 16:15
 */

#ifndef _LINUXFILEINFO_H
#define	_LINUXFILEINFO_H
#include <iostream>
#include <sys/stat.h>
#include <assert.h>
#include <stdexcept>

using namespace std;
namespace std {
class LinuxFileInfo
{
    public:
    static bool canRead(const string& strPath) throw (length_error)
    {
        bool rv = false;
        try
        {
            rv = canAccess(strPath, R_OK);
        }
        catch ( const invalid_argument& e )
        {
            cerr << e.what() << endl;
        }
        return rv;
    }
    static bool canExecute(const string& strPath) throw (length_error)
    {
        bool rv = false;
        try
        {
            rv = canAccess(strPath, X_OK);
        }
        catch ( const invalid_argument& e )
        {
            cerr << e.what() << endl;
        }
        return rv;
    }
    static bool canWrite(const string& strPath) throw (length_error)
    {
        bool rv = false;
        try
        {
            rv = canAccess(strPath, W_OK);
        }
        catch ( const invalid_argument& e )
        {
            cerr << e.what() << endl;
        }
        return rv;
    }
    static bool exists(const string& strPath) throw (length_error)
    {
        bool rv = false;
        try
        {
            rv = canAccess(strPath, F_OK);
        }
        catch ( const invalid_argument& e )
        {
            cerr << e.what() << endl;
        }
        return rv;
    }
    static bool isDirectory(const string& strPath) throw (invalid_argument)
    {
        return S_ISDIR(getMode(strPath));
    }
    static bool isRegularFile(const string& strPath) throw (invalid_argument)
    {
        return S_ISREG(getMode(strPath));
    }
protected:
    static bool canAccess(const string& strPath, int mode) throw ( invalid_argument, length_error )
    {
        assert(mode == F_OK || mode == R_OK || mode == W_OK || mode == X_OK);

        if (mode != F_OK && mode != R_OK && mode != W_OK && mode != X_OK)
        {
            // Should never get here due to the assert above.
            throw invalid_argument("Unknown file mode");
        }
        if (strPath.length()<1)
        {
            throw length_error("File path string too short");
        }
        return 0 == access(strPath.c_str(), mode);
    }
    static mode_t getMode(const string& strPath) throw (invalid_argument)
    {
        struct stat _stat;
        if ( 0 > lstat(strPath.c_str(), &_stat) )
        {
            throw invalid_argument("Unable to stat file");
        }
        return _stat.st_mode;
    }
};


#endif	/* _LINUXFILEINFO_H */

}